/*******************************************************************
 *   > File Name: mkv210_image.c
 *   > Author: fly
 *   > Mail: XXXXXXXX@icode.com
 *   > Create Time: 2020年04月11日 星期六 10时52分44秒
 ******************************************************************/
/*
 *mkv210_image.c的作用:将USB启动时使用的BIN文件制作得到SD卡启动的Image
 *计算文件校验和，添加16字节的文件头，将校验和写入文件头第8字节处
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "debug.h"

#define BUFSIZE                 (16*1024)
#define IMG_SIZE                (16*1024)
#define SPL_HEADER_SIZE         16
#define SPL_HEADER              "****************"

#define SD_FILE_NAME_TAIL       ".sd.bin"
#define SD_FILE_NAME_HEAR       "sd."

#define FILE_PATH_LENGTH_MAX    (128)

int main(int argc, char *argv[])
{
    FILE *fp;
    char *Buf, *a;
    int BufLen;
    int nbytes, fileLen;
    unsigned int checksum, count;
    int i;
    
    //Uage:./a.out src dest
    if((argc != 2) && (argc != 3))
    {
        printf("Usage1: %s <source file>\n",argv[0]);
        printf("Usage2: %s <source file> <destination file>\n",argv[0]);
        return (-1);
    }

    //version
    if(strncmp("--version", argv[1], strlen("--version")) == 0)
    {
        puts("make_image v00.0");
        return 0;
    }

    //malloc 16K buffer
    BufLen = BUFSIZE;
    Buf = (char *)malloc(BufLen);
    if(!Buf)
    {
        puts("Alloc buffer failed!\n");return(-1);
    }
    memset(Buf, 0x00, BufLen);

    //read src file to buffer
    fp = fopen(argv[1], "rb");
    if(fp == NULL)
    {
        printf("%s fail to open:%s\n",argv[1], strerror(errno));
        free(Buf);
        return (-1);
    }

    fseek(fp, 0L, SEEK_END);
    fileLen = ftell(fp);
    fseek(fp, 0L, SEEK_SET);

    count = (fileLen < (IMG_SIZE - SPL_HEADER_SIZE))\
            ?fileLen : (IMG_SIZE - SPL_HEADER_SIZE);

    memcpy(&Buf[0], SPL_HEADER, SPL_HEADER_SIZE);
    
    //read source file to buffer[16]
    nbytes = fread(Buf + SPL_HEADER_SIZE, 1, count ,fp);
    if(nbytes != count)
    {
        printf("source file read error:%s\n", strerror(errno));
        free(Buf);
        fclose(fp);
        return (-1);
    }
    fclose(fp);
    
    //Calculated check sum
    a = Buf + SPL_HEADER_SIZE;
    for(i = 0, checksum = 0; i< IMG_SIZE - SPL_HEADER_SIZE; i++)
    {
        checksum += (0x000000FF) & *a++;
    }
    a = Buf + 8;
    *((unsigned int *)a ) = checksum;

    //copy buffer to destination file
    char new_file_path[FILE_PATH_LENGTH_MAX] = {0};
    if(argc == 2)
    {
        snprintf(new_file_path, FILE_PATH_LENGTH_MAX, "%s%s", argv[1], SD_FILE_NAME_TAIL);   
        //snprintf(new_file_path, FILE_PATH_LENGTH_MAX, "%s%s",SD_FILE_NAME_HEAR , argv[1]);   //Add file name head
    }
    else if(argc == 3)
    {
        snprintf(new_file_path, FILE_PATH_LENGTH_MAX, "%s", argv[2]);
    }

    fp = fopen(new_file_path, "wb+");
    if(fp == NULL)
    {
        printf("%s file to open:%s\n", new_file_path, strerror(errno));
        free(Buf);
        return (-1);
    }

    a = Buf;
    nbytes = fwrite(a, 1, BufLen, fp);
    if(nbytes != BufLen)
    {
        printf("destination file write error :%s\n",strerror(errno));
        free(Buf);
        fclose(fp);
        return (-1);
    }

    printf(GREEN"the checksum is 0X%X for %d bytes\noutput file: %s\n"NONE, \
            checksum, fileLen, new_file_path);

    free(Buf);
    fclose(fp);

    //DBG_PRINTF("make image end.\n");

    return 0;
}
